package com.markhsiu.MiniMQ.remote.transport.netty;

import java.util.HashMap;
import java.util.Map;

import com.markhsiu.MiniMQ.model.constant.MessageSourceEnum;
import com.markhsiu.MiniMQ.remote.MessageHandler;
import com.markhsiu.MiniMQ.remote.Server;
import com.markhsiu.MiniMQ.remote.URL;
import com.markhsiu.MiniMQ.remote.transport.netty.handler.CustomerNettyMessageHandler;
import com.markhsiu.MiniMQ.remote.transport.netty.handler.NettySeverHandler;
import com.markhsiu.MiniMQ.remote.transport.netty.handler.ProducerNettyMessageHandler;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.serialization.ClassResolvers;
import io.netty.handler.codec.serialization.ObjectDecoder;
import io.netty.handler.codec.serialization.ObjectEncoder;

/**
 * Created by Mark Hsiu on 2017/2/8.
 */
public class NettyServer implements Server{

    private  EventLoopGroup boss = new NioEventLoopGroup();
    private  EventLoopGroup worker = new NioEventLoopGroup();
    private static final Map<MessageSourceEnum, MessageHandler> handlers = new HashMap<>();

    private URL url;

    public NettyServer(){
        url = new URL();
    }

    public  NettyServer(URL url){
        if(url == null){
            throw new RuntimeException(" url is null");
        }
        this.url = url;
    }

    @Override
    public URL getURL() {
        return url;
    }

    @Override
    public void open() {
    	handlers.put(MessageSourceEnum.CUSTOMER, new CustomerNettyMessageHandler());
        handlers.put(MessageSourceEnum.PRODUCER, new ProducerNettyMessageHandler());
         
        ServerBootstrap bootstrap = new ServerBootstrap();
        bootstrap.group(boss,worker)
                .channel(NioServerSocketChannel.class)
                .option(ChannelOption.SO_BACKLOG,1024)
                .childHandler(new ChildChannelHandler());

        try {
            ChannelFuture future = bootstrap.bind(url.getPort()).sync();
            future.channel().closeFuture().sync();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        
       
    }

    @Override
    public void close() {
        worker.shutdownGracefully();
        boss.shutdownGracefully();
    }


    private class ChildChannelHandler extends ChannelInitializer<SocketChannel>{

        @Override
        protected void initChannel(SocketChannel channel) throws Exception {
            ChannelPipeline pip = channel.pipeline();
            // 1.
            // 负责实现Serializable的POJO对象进行解码，它有多个构造函数，支持不同的ClassResolver
            // 2.
            // 在此我们使用weakCachingConcurentResolver创建线程安全的WeakReferenceMap对象类加载器
            // 进行缓存，它支持多线程并发访问，当虚拟机内存不足时，会释放缓存中的内存，防止内存泄漏
            // 3.
            // 为了防止异常码流和解码错位导致的内存溢出，这里将单个对象最大序列化后的字节数组长度设置为1M,作为例程足够了。
            pip.addLast(new ObjectDecoder(1024 * 1024,
                    ClassResolvers.weakCachingConcurrentResolver(this.getClass().getClassLoader())));
            pip.addLast(new ObjectEncoder());

            pip.addLast(new NettySeverHandler(handlers));
        }
    }

}
